﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ParametersViewModel.cs" company="R.V.Kasner">
//   Copyright © 2011 R.V.Kasner
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Owen.Terminal.ViewModel
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;

    using GalaSoft.MvvmLight.Command;

    using Microsoft.Practices.Prism.Events;

    using Owen.Communication.Protocols;
    using Owen.Communication.Service;
    using Owen.Terminal.Commons;
    using Owen.Terminal.Events;
    using Owen.Terminal.Services;
    using Owen.Terminal.View;

    public class ParametersViewModel : ViewModelBase<IParametersView>, IParametersViewModel
    {
        private readonly IEventAggregator eventArg;

        private readonly ObservableCollection<ParameterViewModel> items;

        private readonly OnePackManager packManager;

        private readonly PackageConstructor packageConstructor;

        private readonly VisualCommand[] visCommands;

        private bool isTransmit;

        public ParametersViewModel()
        {
            this.items = new ObservableCollection<ParameterViewModel>
                {
                    new ParameterViewModel(
                        new Parameter(
                        "15", true, "int", "Параметр int", 4, 6, "aoeu", 25, ParameterTypes.Int, false)), 
                    new ParameterViewModel(
                        new Parameter(
                        "5.1", false, "float", "Параметр float", 4, 12, "A.hre", 121, ParameterTypes.Float, true)), 
                    new ParameterViewModel(
                        new Parameter(
                        "Abs", true, "string", "Параметр string", 8, 5, "str", 284, ParameterTypes.StringAscii, false)), 
                };
        }

        public ParametersViewModel(
            IParametersView view,
            IEventAggregator eventArg,
            PackageConstructor packageConstructor,
            ITransmitter transmitter)
            : base(view)
        {
            this.items = new ObservableCollection<ParameterViewModel>();

            this.eventArg = eventArg;
            this.packageConstructor = packageConstructor;
            this.View.Selected += this.OnSelected;
            this.visCommands = this.CreateCommands();
            this.isTransmit = false;
            this.packManager = new OnePackManager(this.packageConstructor);
            this.eventArg.GetEvent<ReceivePackageEvent>().Subscribe(this.packManager.HeadTransmitPack);
            this.packManager.NotValidPack += m => this.eventArg.GetEvent<WriteToLogEvent>().Publish(m);
            this.packManager.ParameterValueRead +=
                triplet => this.eventArg.GetEvent<ParameterValueReadEvent>().Publish(triplet);

            transmitter.Stoped += this.packManager.OnTransmitStoped;
            transmitter.Transmited += p => this.packManager.OnTransmitTransmited();

            if (this.IsInDesignMode)
            {
                return;
            }

            this.eventArg.GetEvent<ConnectChangeEvent>().Subscribe(
                cs =>
                {
                    this.isTransmit = (cs & SignallerStates.Transmit) == SignallerStates.Transmit;
                    this.RaisePropertyChanged("IsEditable");
                });
            this.eventArg.GetEvent<FavoriteCicleReadEvent>().Subscribe(o => this.OnReadFivoritesCicle());
        }

        public bool IsEditable
        {
            get
            {
                return !this.isTransmit;
            }
        }

        public IEnumerable<ParameterViewModel> Items
        {
            get
            {
                return this.items;
            }
        }

        public ParameterViewModel SelectedParam { get; set; }

        public void LoadParameters(IEnumerable<Parameter> parameters)
        {
            this.CreateParamList(parameters);
        }

        public void CommandPackToTransmit(int[] pack)
        {
            if (this.packManager.IsRunning)
            {
                this.packManager.SetCommandPack(pack);
            }
            else
            {
                var transData = new TransmitData(new HermitTransferHead(pack), false);
                this.eventArg.GetEvent<TransmitStartEvent>().Publish(transData);
            }
        }

        private VisualCommand[] CreateCommands()
        {
            return new[]
                {
                    new VisualCommand
                        {
                           Command = new RelayCommand(this.OnReadAll, () => !this.isTransmit), Title = "Прочитать всё", 
                        }, 
                    new VisualCommand
                        {
                           Command = new RelayCommand(this.OnWriteAll, () => !this.isTransmit), Title = "Записать всё", 
                        }, 
                    new VisualCommand
                        {
                            Command =
                                new RelayCommand(
                                this.OnReadCurrent, () => !this.isTransmit && this.SelectedParam != null && !this.IsUnavailable(this.SelectedParam)), 
                            Title = "Прочитать текущий", 
                        }, 
                    new VisualCommand
                        {
                            Command =
                                new RelayCommand(
                                this.OnWriteCurrent, 
                                () =>
                                !this.isTransmit && this.SelectedParam != null &&
                                !this.SelectedParam.Parameter.IsReadOnly && !this.IsUnavailable(this.SelectedParam)), 
                            Title = "Записать текущий", 
                        },
                };
        }

        private void CreateParamList(IEnumerable<Parameter> dataParams)
        {
            foreach (var paramVwMdl in this.items)
            {
                paramVwMdl.FavoriteChanged -= this.OnParamVmFavoriteChanged;
            }

            var favorites = new List<ParameterViewModel>();

            this.items.Clear();
            foreach (var dataParam in dataParams)
            {
                var pvm = new ParameterViewModel(dataParam);
                pvm.FavoriteChanged += this.OnParamVmFavoriteChanged;
                this.items.Add(pvm);

                if (pvm.IsFavorite)
                {
                    ////this.OnParamVmFavoriteChanged(pvm);
                    favorites.Add(pvm);
                }
            }

            this.eventArg.GetEvent<OpenParametersFileEvent>().Publish(favorites);
        }

        private bool IsUnavailable(ParameterViewModel paramvm)
        {
            if (this.packageConstructor.Protocol is OwenBus)
            {
                if (!paramvm.Parameter.IsOwenSupport)
                {
                    return true;
                }
            }

            return false;
        }

        private void OnParamVmFavoriteChanged(ParameterViewModel arg1)
        {
            this.eventArg.GetEvent<FavoriteChangedEvent>().Publish(arg1);
        }

        private void OnReadAll()
        {
            var newList = this.items.Where(pvm => !this.IsUnavailable(pvm)).ToList();
            if (newList.Count == 0)
            {
                return;
            }

            this.packManager.SetUp(newList, false, false);

            var transData = new TransmitData(this.packManager.Head, false);
            this.eventArg.GetEvent<TransmitStartEvent>().Publish(transData);
        }

        private void OnReadFivoritesCicle()
        {
            var newList = this.items.Where(pvm => !this.IsUnavailable(pvm) && pvm.IsFavorite).ToList();
            if (newList.Count == 0)
            {
                return;
            }

            this.packManager.SetUp(newList, false, true);

            var transData = new TransmitData(this.packManager.Head, true);
            this.eventArg.GetEvent<TransmitStartEvent>().Publish(transData);
        }

        private void OnReadCurrent()
        {
            if (this.SelectedParam == null)
            {
                return;
            }

            if (this.IsUnavailable(this.SelectedParam))
            {
                return;
            }

            this.packManager.SetUp(new List<ParameterViewModel> { this.SelectedParam }, false, false);

            var transData = new TransmitData(this.packManager.Head, false);
            this.eventArg.GetEvent<TransmitStartEvent>().Publish(transData);
        }

        private void OnSelected()
        {
            this.eventArg.GetEvent<VisualCommandsChangeEvent>().Publish(this.visCommands);
        }

        private void OnWriteAll()
        {
            var newList = this.items.Where(pvm => !pvm.Parameter.IsReadOnly && !this.IsUnavailable(pvm)).ToList();
            if (newList.Count == 0)
            {
                return;
            }

            this.packManager.SetUp(newList, true, false);

            var transData = new TransmitData(this.packManager.Head, false);
            this.eventArg.GetEvent<TransmitStartEvent>().Publish(transData);
        }

        private void OnWriteCurrent()
        {
            if (this.SelectedParam == null)
            {
                return;
            }

            if (this.IsUnavailable(this.SelectedParam))
            {
                return;
            }

            this.packManager.SetUp(new List<ParameterViewModel> { this.SelectedParam }, true, false);

            var transData = new TransmitData(this.packManager.Head, false);
            this.eventArg.GetEvent<TransmitStartEvent>().Publish(transData);
        }
    }
}